﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;

using System.Windows.Media;
using System.Windows.Shapes;
using Microsoft.Win32;
using XCSerialPort;
using Path = System.IO.Path;

namespace SmartSwitch_StressTest
{
    public partial class MainWindow : Window
    {
        private SerialPort_ARM_ISPManager _serialManager;
    
        private bool _isTesting = false;
        // 在类成员中定义日志文件路径变量
        private string logFilePath;
        // 导入 Windows API
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);

        [Flags]
        public enum EXECUTION_STATE : uint
        {
            ES_AWAYMODE_REQUIRED = 0x00000040,
            ES_CONTINUOUS = 0x80000000,
            ES_DISPLAY_REQUIRED = 0x00000002,
            ES_SYSTEM_REQUIRED = 0x00000001
        }


        public MainWindow()
        {
            InitializeComponent();
            InitializeControls();
            InitializeSerialManager();
            Loaded += MainWindow_Loaded;
            Closed += MainWindow_Closed;
        }



        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            // 阻止屏幕关闭和系统休眠
            SetThreadExecutionState(EXECUTION_STATE.ES_DISPLAY_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS);
        }

        private void MainWindow_Closed(object sender, EventArgs e)
        {
            // 恢复系统默认电源管理
            SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS);
        }
        private void InitializeControls()
        {
          

            // 绑定按钮事件
            btnRefreshPorts.Click += (s, e) => RefreshSerialPorts();
            btnOpenPort.Click += BtnOpenPort_Click;
            btnStartTest.Click += BtnStartTest_Click;
            btnExportLog.Click += BtnExportLog_Click;
            btnFileWrite.Click += BtnFileWrite_Click;
            btnReadRegister.Click += BtnReadRegister_Click;
            btnWriteRegister.Click += BtnWriteRegister_Click;

        }

        private void InitializeSerialManager()
        {
            _serialManager = new SerialPort_ARM_ISPManager();
            RefreshSerialPorts();
        }

        private void RefreshSerialPorts()
        {
            cmbPortName.Items.Clear();
            string[] ports = _serialManager.GetSerialPorts(out string msg);

            foreach (string port in ports)
            {
                cmbPortName.Items.Add(port);
            }

            if (cmbPortName.Items.Count > 0)
            {
                cmbPortName.SelectedIndex = 0;
            }

            UpdateStatus(msg);
        }

        private void BtnOpenPort_Click(object sender, RoutedEventArgs e)
        {
            try
            {
             
                if (_serialManager.IsOpen())
                {
                    _serialManager.Close(out string msg);
                    AppendLog(msg);
                    btnOpenPort.Content = "打开端口";
                    btnStartTest.IsEnabled = false;
                    UpdateStatus(msg);
                }
                else
                {
                    var config = new ConfigType
                    {
                        PortName = cmbPortName.SelectedItem?.ToString(),
                        BaudRate = int.Parse(((ComboBoxItem)cmbBaudRate.SelectedItem).Content.ToString()),
                        DataBits = 8,
                        StopBits = (StopBits)1, // One
                        Parity = (Parity)2    // Even
                    };
                    _serialManager = new SerialPort_ARM_ISPManager(config);
                    if (_serialManager.Open(out string msg))
                    {
                        AppendLog(msg);
                        btnOpenPort.Content = "关闭端口";
                        btnStartTest.IsEnabled = true;
                        UpdateStatus($"已连接 {config.PortName}@{config.BaudRate}");
                    }
                    else
                    {
                        MessageBox.Show(msg, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"串口操作错误: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                UpdateStatus("错误: " + ex.Message);
            }
        }

        private void BtnStartTest_Click(object sender, RoutedEventArgs e)
        {
            if (!_serialManager.IsOpen())
            {
                MessageBox.Show("请先打开串口", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            _isTesting = !_isTesting;

            

            if (_isTesting)
            {
                // 清空文本框内容
                txtReceive.Clear();
                // 使用程序运行目录作为日志存储路径
                string logDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs");
                // 生成包含日期的日志文件名
                string currentDate = DateTime.Now.ToString("yyyyMMdd_HHmmsss");
                logFilePath = Path.Combine(logDirectory, $"application_{currentDate}.log");
                // 确保日志目录存在
                if (!Directory.Exists(logDirectory))
                {
                    Directory.CreateDirectory(logDirectory);
                }

                // 如果日志文件已经存在，则清空内容
                if (File.Exists(logFilePath))
                {
                    File.WriteAllText(logFilePath, string.Empty); // 清空文件内容
                }

                btnStartTest.Content = "停止测试";
                //btnStartTest.IsEnabled = false;  // 禁用按钮
                StartStressTest();
            }
            else
            {
                StopStressTest();
                btnStartTest.Content = "开始测试";
                //btnStartTest.IsEnabled = true;  // 启用按钮
            }
        }

        private async void StartStressTest()
        {
            AppendLog("=== 压力测试开始 ===");
            UpdateStatus("压力测试进行中...");

            var tSleep = Convert.ToInt32(_txtSleep.Text)*1000;
            var tCount = Convert.ToInt16(_txtCount.Text);
            var tOutpic = Convert.ToInt16(_txtOutPic.Text) * 1000;
            // 如果输入值等于0，立即停止测试
            if (tCount <= 0)
            {
                AppendLog("测试次数必须大于0。");
                _isTesting = false; // 确保测试状态为停止
                btnStartTest.Content = "开始测试";
                btnStartTest.IsEnabled = true;  // 启用按钮
                return; // 退出方法
            }

            string lastTransferMode = string.Empty;
            string lastVideoFormat = string.Empty;
            DateTime startTime = DateTime.Now; // 记录开始时间

            for (int i = 1; i <= tCount; i++) // 进行多次测试
            {
                // 检查用户是否点击了停止按钮
                if (!_isTesting)
                {
                    AppendLog("测试已被用户取消。");
                    break; // 用户点击了停止按钮，退出循环
                }


                ulong previousFrameCount = 0;
                bool isVideoStreamActive = true;

                // 获取当前的出图制式和尺寸
                string transferMode = GetTransferMode();
                string videoFormat = GetVideoFormat();
                string sizeInfo = $"{transferMode}-{videoFormat}"; // 示例尺寸信息

                // 检查制式切换
                if (transferMode == lastTransferMode && videoFormat == lastVideoFormat)
                {
                    AppendLog("制式切换失败，软件报错：Setting轮询功能配置异常或无OSD菜单，制式切换失败");
                    return; // 停止测试
                }

                lastTransferMode = transferMode;
                lastVideoFormat = videoFormat;

                // 读取 nISPFrameCnt 寄存器并验证
                for (int j = 0; j < 3; j++)
                {
                    await Task.Delay(300); // 等待300毫秒

                    try
                    {
                        // 读取 nISPFrameCnt 寄存器
                        var values = _serialManager.ReadRegister1(0x20000020, out string msg, 4, 500);
                        AppendLog($"第一次 {msg}");
                        ulong currentFrameCount = values[0];
                        AppendLog($"\n第一次 地址0x20000020-0023 当前值：0x{currentFrameCount:X} 历史值:0x{previousFrameCount:X}");
                        
                        if (previousFrameCount > 0 && currentFrameCount <= previousFrameCount)
                        {
                            AppendLog("ISP视频流输出异常！！！");
                            isVideoStreamActive = false;
                            previousFrameCount = currentFrameCount;
                            break; // 如果没有累加则停止当前测试
                        }
                        previousFrameCount = currentFrameCount;

                    }
                    catch (Exception ex)
                    {
                        AppendLog($"读取寄存器失败: {ex.Message}", Colors.Red);
                        isVideoStreamActive = false;
                        break; // 或者选择继续下一个测试
                    }
                }

                if (!isVideoStreamActive)
                {
                    previousFrameCount = 0;
                    isVideoStreamActive = true;
                    var values1 = _serialManager.ReadRegister(0x80c00001, out string msg1, 1, 500);
                    AppendLog($"地址0x80c00001 当前值：0x{values1[0]:X} ");
                    AppendLog($"检测到卡死 等待2秒");
                    await Task.Delay(2000);
                    for (int j = 0; j < 3; j++)
                    {
                        await Task.Delay(300); // 等待300毫秒

                        try
                        {
                            // 读取 nISPFrameCnt 寄存器
                            var values = _serialManager.ReadRegister(0x20000020, out string msg, 4, 500);
                            AppendLog($"第二次 {msg}");
                            ulong currentFrameCount = values[0];
                            AppendLog($"\n第二次 地址0x20000020-0023 当前值：0x{currentFrameCount:X} 历史值:0x{previousFrameCount:X}");

                            if (previousFrameCount >0 && currentFrameCount <= previousFrameCount)
                            {
                                AppendLog(" 第二次 ISP视频流输出异常！！！");
                                isVideoStreamActive = false;
                                previousFrameCount = currentFrameCount;
                                break; // 如果没有累加则停止当前测试
                            }
                              
                            previousFrameCount = currentFrameCount;
                        }
                        catch (Exception ex)
                        {
                            AppendLog($"读取寄存器失败: {ex.Message}", Colors.Red);
                            isVideoStreamActive = false;
                            break; // 或者选择继续下一个测试
                        }
                    }
                }

                var values8 = _serialManager.ReadRegister(0x80c00001, out string msg8, 1, 500);
                AppendLog($"地址0x80c00001 当前值：0x{values8[0]:X} ");

                // 写入寄存器
                try
                {
                    _serialManager.WriteRegister(0x80260027, new List<ulong> { 0xff }, out string msg1, 1, 500);
                    await Task.Delay(1);
                    _serialManager.WriteRegister(0x80260021, new List<ulong> { 0xff }, out string msg2, 1, 500);
                    await Task.Delay(1);
                    _serialManager.WriteRegister(0x80260021, new List<ulong> { 0x00 }, out string msg4, 1, 500);
                    await Task.Delay(1);
                    //AppendLog(msg1+" "+msg2+" "+ msg4);
                }
                catch (Exception ex)
                {
                    AppendLog($"写入0x80260027\\0x80260021寄存器失败: {ex.Message}", Colors.Red);
                    continue; // 如果写入失败，跳过后续操作
                }

                // 读取 MIPIRX 状态
                var mipiVal = _serialManager.ReadRegister(0x80260030, out string msg3, 1, 500);
                //AppendLog(msg3);
                var mipirxStatus = (mipiVal[0] == 0x0) ? "pass" : "fail"; // 读取状态并判断

                // 记录测试持续时间
                TimeSpan testDuration = DateTime.Now - startTime;
                string testEndTime = DateTime.Now.ToString("yyyy_MM_dd HH_mm_ss");
                var VideoStreamActiveStatus = isVideoStreamActive ? "累加" : "卡死";

                // 格式化日志信息
                string logEntry = $"\n第{i}次测试，测试结果：{mipirxStatus}；\n" +
                                  $"尺寸信息：{sizeInfo}；\n" +
                                  $"ISP帧计数信息：{VideoStreamActiveStatus}；\n" +
                                  $"MIPIRX的状态：0x80260030 = 0x{mipiVal[0]:X}；\n" +
                                  $"测试时间：{testDuration.Hours}小时{testDuration.Minutes}分钟{testDuration.Seconds}秒，\n" +
                                  $"系统时间：{testEndTime}；\n";

                AppendLog(logEntry); // 输出日志信息
                AppendLog("/**********************************************/"); // 每次测试结束的分隔线

                await Task.Delay(tOutpic); //出图显示时间可配置
                if (!_isTesting)
                {
                    AppendLog("测试已被用户取消。");
                    break; // 用户点击了停止按钮，退出循环
                }
                //截取桌面图片
                if ((bool)isScreenshot.IsChecked && !string.IsNullOrEmpty(_txtScreenshot.Text))
                {
                    // 组合文件名与路径
                    string filePath = Path.Combine(_txtScreenshot.Text, $"{sizeInfo}_{i}_{testEndTime}.jpg");
                    CaptureScreen(filePath, out string fileMsg);
                    AppendLog(fileMsg);
                }
                if (!isVideoStreamActive && (bool)isKasi_Check.IsChecked)
                {
                    return;
                }

                // 写入1到 Flag_Key_Down 寄存器
                _serialManager.WriteRegister(0x2000140f, new List<ulong> { 0x1 }, out string writeMsg);
                //AppendLog(writeMsg);
               

                // 切换制式操作并验证
                int unsuccessfulAttempts = 0;

                for (int k = 0; k < 5; k++)
                {
                    if (!_isTesting)
                    {
                        AppendLog("测试已被用户取消。");
                        break; // 用户点击了停止按钮，退出循环
                    }
                    try
                    {
                       

                        await Task.Delay(20); // 延时20毫秒

                        // 读取Flag_Key_Down寄存器以验证
                        var flagValue = _serialManager.ReadRegister(0x2000140f, out string flagMsg, 1, 500);
                        //AppendLog(flagMsg);

                        // 如果寄存器值未被置回0
                        if (flagValue[0] != 0)
                        {
                            unsuccessfulAttempts++;
                            AppendLog($"尝试{k + 1}: 功能异常，Flag_Key_Down寄存器未置为0", Colors.Red);
                        }
                        else
                        {
                            // 如果成功置为0，则可以退出循环
                            AppendLog("Flag_Key_Down寄存器成功置为0");
                            break;
                        }
                    }
                    catch (Exception ex)
                    {
                        AppendLog($"切换制式操作失败: {ex.Message}", Colors.Red);
                        return; // 停止测试
                    }
                }

                // 如果5次尝试都没有成功置为0，报错
                if (unsuccessfulAttempts >= 5)
                {
                    AppendLog("功能异常，制式切换失败", Colors.Red);
                }

                // 等待用户配置的延时
                await Task.Delay(tSleep);
            }

            _isTesting = false;
            //AppendLog("=== 压力测试结束 ===");
        }


        // 获取当前传输模式
        private string GetTransferMode()
        {
            var values = _serialManager.ReadRegister(0x2000143f, out string msg, 1, 500);
            //AppendLog(msg);
            var tlist = VideoHelper.GetTransferMode();

            // 使用 LINQ 查询，确保不区分大小写，并添加空检查
            var transferMode = tlist.FirstOrDefault(c =>
                string.Equals(c.Hex, "0x" + values[0].ToString("X2"), StringComparison.OrdinalIgnoreCase));

            return transferMode != null ? transferMode.Name : "未知模式"; // 如果没有找到，则返回"未知模式"
        }

        // 获取当前视频制式
        private string GetVideoFormat()
        {
            var values = _serialManager.ReadRegister(0x20001440, out string msg, 1, 500);
            //AppendLog(msg);
            var vlist = VideoHelper.GetVideoMode();

            // 使用 LINQ 查询，确保不区分大小写，并添加空检查
            var videoFormat = vlist.FirstOrDefault(c =>
                string.Equals(c.Hex, "0x" + values[0].ToString("X2"), StringComparison.OrdinalIgnoreCase));

            return videoFormat != null ? videoFormat.Name : "未知制式"; // 如果没有找到，则返回"未知制式"
        }




        private void StopStressTest()
        {
            // 记录测试结束日志
            AppendLog("=== 压力测试结束 ===");
            UpdateStatus("压力测试已停止");

            // 设置测试状态为停止
            _isTesting = false;

            // 更新UI状态，例如启用/禁用按钮
            btnStartTest.Content = "开始测试";
            btnStartTest.IsEnabled = true; // 启用按钮
        }


        private void BtnReadRegister_Click(object sender, RoutedEventArgs e)
        {
            if (!_serialManager.IsOpen())
            {
                MessageBox.Show("请先打开串口", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            try
            {
                string addrText = _txtRegAddress.Text.Replace(" ", "");
                if (string.IsNullOrEmpty(addrText) || addrText.Length != 8)
                {
                    MessageBox.Show("请输入有效的8位十六进制地址", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                    return;
                }

                ulong addr = Convert.ToUInt32(addrText,16);
                var values = _serialManager.ReadRegister(addr, out string msg, 1, 500);
                _txtRegValue.Text = $"{values[0]:X2}";
                AppendLog($"读取寄存器 0x{addr:X8} 值: 0x{values[0]:X}");
                UpdateStatus(msg);
            }
            catch (Exception ex)
            {
                AppendLog($"读取寄存器失败: {ex.Message}", Colors.Red);
            }
        }

        private void BtnWriteRegister_Click(object sender, RoutedEventArgs e)
        {
            if (!_serialManager.IsOpen())
            {
                MessageBox.Show("请先打开串口", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            try
            {
                string addrText = _txtRegAddress.Text.Replace(" ", "");
                string valueText = _txtRegValue.Text.Replace(" ", "");

                if (string.IsNullOrEmpty(addrText) || addrText.Length != 8)
                {
                    MessageBox.Show("请输入有效的8位十六进制地址", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                    return;
                }

                if (string.IsNullOrEmpty(valueText) || valueText.Length > 8)
                {
                    MessageBox.Show("请输入有效的十六进制值(最多8位)", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                    return;
                }

                ulong addr = Convert.ToUInt64(addrText, 16);
                ulong value = Convert.ToUInt64(valueText, 16);

                _serialManager.WriteRegister(addr, new List<ulong> { value }, out string msg);

                AppendLog($"写入寄存器 0x{addr:X8} 值: 0x{value:X8}");
                UpdateStatus(msg);
            }
            catch (Exception ex)
            {
                AppendLog($"写入寄存器失败: {ex.Message}", Colors.Red);
            }
        }

        private void BtnFileWrite_Click(object sender, RoutedEventArgs e)
        {
            var openFileDialog = new OpenFileDialog
            {
                Filter = "二进制文件 (*.bin)|*.bin|所有文件 (*.*)|*.*"
            };

            if (openFileDialog.ShowDialog() == true)
            {
                try
                {
                    byte[] fileData = File.ReadAllBytes(openFileDialog.FileName);
                    AppendLog($"准备写入文件: {openFileDialog.FileName} ({fileData.Length}字节)");

                    // 这里添加实际的文件写入逻辑
                    // 例如: _serialManager.WriteRawData(fileData, out string msg);
                }
                catch (Exception ex)
                {
                    AppendLog($"文件操作错误: {ex.Message}", Colors.Red);
                }
            }
        }

        private void BtnExportLog_Click(object sender, RoutedEventArgs e)
        {
           
            // 检查日志文件是否存在
            if (!File.Exists(logFilePath))
            {
                MessageBox.Show("没有可导出的日志文件", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
                return;
            }

            // 创建保存文件对话框
            var saveFileDialog = new SaveFileDialog
            {
                Filter = "文本文件 (*.txt)|*.txt|所有文件 (*.*)|*.*",
                FileName = $"测试日志_{DateTime.Now:yyyyMMddHHmmss}.txt"
            };

            if (saveFileDialog.ShowDialog() == true)
            {
                try
                {
                    // 读取日志文件内容
                    string logContent = File.ReadAllText(logFilePath);
                    // 写入用户指定的文件
                    File.WriteAllText(saveFileDialog.FileName, logContent);
                    AppendLog($"日志已导出到: {saveFileDialog.FileName}");
                }
                catch (Exception ex)
                {
                    AppendLog($"导出日志失败: {ex.Message}", Colors.Red);
                }
            }
        }

        private void AppendLog(string message, Color? color = null)
        {
            // 确保在UI线程执行
            if (!Dispatcher.CheckAccess())
            {
                Dispatcher.Invoke(() => AppendLog(message, color));
                return;
            }

            string timestamp = $"[{DateTime.Now:MM-dd  HH:mm:ss}] ";
            string logMessage = timestamp + message;

            // 立即更新UI
            txtReceive.AppendText(logMessage + Environment.NewLine);
            txtReceive.ScrollToEnd();

            // 异步写入文件，不阻塞UI
            Task.Run(() => WriteLogToFile(logMessage));
        }

        private void WriteLogToFile(string logMessage)
        {
            string logDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs");

            try
            {
                if (!string.IsNullOrEmpty(logFilePath))
                {
                    Directory.CreateDirectory(logDirectory);
                    File.AppendAllText(logFilePath, logMessage + Environment.NewLine);
                }
               
            }
            catch (Exception ex)
            {
                Dispatcher.Invoke(() => txtReceive.AppendText($"日志写入失败: {ex.Message}{Environment.NewLine}"));
            }
        }

        private void UpdateStatus(string message)
        {
            Dispatcher.Invoke(() => txtStatus.Text = message);
        }

        // 辅助方法：查找可视化子元素
        private IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
        {
            if (depObj != null)
            {
                for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
                {
                    DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
                    if (child != null && child is T)
                    {
                        yield return (T)child;
                    }

                    foreach (T childOfChild in FindVisualChildren<T>(child))
                    {
                        yield return childOfChild;
                    }
                }
            }
        }

        protected override void OnClosed(EventArgs e)
        {
            if (_serialManager != null && _serialManager.IsOpen())
            {
                _serialManager.Close(out _);
            }
            base.OnClosed(e);
        }

        /// <summary>
        /// 清空文本
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BtnClear_Click(object sender, RoutedEventArgs e)
        {
            txtReceive.Clear(); // 清除文本框的内容
        }

        /// <summary>
        /// 打开文件夹
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void openFile_Click(object sender, RoutedEventArgs e)
        {
            var dialog = new Microsoft.WindowsAPICodePack.Dialogs.CommonOpenFileDialog
            {
                IsFolderPicker = true,
                Title = "选择文件夹"
            };

            if (dialog.ShowDialog() == Microsoft.WindowsAPICodePack.Dialogs.CommonFileDialogResult.Ok)
            {
                string selectedFolder = dialog.FileName;
                _txtScreenshot.Text = selectedFolder;
            }


        }

        private bool CaptureScreen(string filePath,out string msg)
        {
            try
            {
                // 获取屏幕尺寸
                System.Drawing.Rectangle bounds = System.Windows.Forms.Screen.GetBounds(System.Drawing.Point.Empty);

                // 创建一个与屏幕大小相同的位图
                using (System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap((int)bounds.Width, (int)bounds.Height))
                {
                    using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bitmap))
                    {
                        // 将屏幕绘制到位图上
                        g.CopyFromScreen(System.Drawing.Point.Empty, System.Drawing.Point.Empty, bounds.Size);
                    }

                    bitmap.Save(filePath, System.Drawing.Imaging.ImageFormat.Jpeg);
                    msg = $"Screenshot saved to {filePath}";
                }
                return true; // 截图成功
            }
            catch (Exception ex)
            {

                msg = $"Error capturing screenshot: {ex.Message}";
                return false; // 截图失败
            }
        }

       
    }
}